package mymyoux.core
{
	import flash.events.EventDispatcher;
	import flash.net.SharedObject;
	
	import mymyoux.events.HashEvent;
	import mymyoux.utils.Hash;
	/**
	 * Classe permettant la gestion de variables et leurs mises en cache.
	 * @author Mymyoux
	 * @version 1.0
	 */
	public class Vars
	{
		/**
		 * HashTable contenant les variables enregistrées.
		 */
		protected var hash:Hash;
		/**
		 * Tableau contenant la liste des variables devant être enregistrées dans le cache.
		 */
		protected var cached:Array;
		/**
		 * @private
		 */
		protected var _cacheName:String;
		/**
		 * SharedObject.
		 */
		protected var sharedObject:SharedObject;
		/**
		 * EventDispatcher permettant le dispatche d'un évènement lors de la mise à jour d'une variable.
		 */
		protected var eventDispatcher:EventDispatcher;
		/**
		 * Crée un objet de type Vars.
		 */
		public function Vars()
		{
			hash=new Hash();
			cached=new Array();
			cacheName="default";
			eventDispatcher=new EventDispatcher();
			hash.addEventListener(HashEvent.UPDATE,onUpdate);
			hash.addEventListener(HashEvent.REMOVE,onUpdate);
		}
		/**
		 * Efface toutes les variables et les démarquent.
		 */
		public function clear():void
		{
			hash.clear();
			cached=new Array();
		}
		/**
		 * Crée ou met à jour une variable.
		 * @param name Nom de la variable.
		 * @param value Valeur de la variable.
		 * Si la variable est marquée comme <code><b>cached</b></code> alors elle est enregistrée dans le cache.
		 * @see #save()
		 */
		public function put(name:String,value:*):void
		{
			hash.put(name,value);
			if(cached.indexOf(name)>-1)
			{
				save(name);
			}
		}
		/**
		 * Récupère la valeur d'une variable.
		 * @param name Nom de la variable.
		 * @return La valeur de la variable ou null si elle n'existe pas.
		 */
		public function get(name:String):*
		{
			return hash.get(name);
		}
		/**
		 * Supprime une variable.
		 * @param name Nom de la variable.
		 * Supprime la variable correspondante si elle existe. Ne supprime pas son marquage <code><b>cached</b></code>, mais appel <code><b>unsave</b></code>.
		 * @see #unsave()
		 */
		public function rem(name:String):void
		{
			if(contains(name))
			{
				hash.remove(name);
				if(cached.indexOf(name)>-1)
				{
					unsave(name);
				}
			}
		}
		/**
		 * Renvoie un boolean qui indique si la variable existe ou non.
		 * @param name Nom de la variable.
		 * @return <code><b>true</b></code> si la variable existe, <code><b>false</b></code> sinon.
		 */
		public function contains(name:String):Boolean
		{
			return hash.containsKey(name);
		}
		
		public function set cacheName(value:String):void
		{
			if(_cacheName!=value)
			{
				_cacheName=value;
				sharedObject=SharedObject.getLocal(value);
				hash.clear();
				for(var p:String in sharedObject.data)
				{
					put(p,sharedObject.data[p]);
					cache(p);
				}
				for(p in cached)
				{
					save(cached[p]);
				}
			}
		}
		/**
		 * Nom du cache.
		 */
		public function get cacheName():String
		{
			return _cacheName;
		}
		/**
		 * Ajoute une variable dans le cache et la marqué <code><b>cached</b></code>.
		 * @param name Nom de la variable.
		 */
		public function cache(name:String):void
		{
			if(cached.indexOf(name)==-1)
			{
				cached.push(name);
				if(contains(name))
				{
					save(name);
				}
			}
		}
		/**
		 * Retire une variable du cache et la démarque.
		 * @param name Nom de la variable.
		 */
		public function uncache(name:String):void
		{
			if(cached.indexOf(name)>-1)
			{
				cached.splice(cached.indexOf(name),1);
				unsave(name);
			}
		}
		/**
		 * Sauvegarde une variable marquée <code><b>cached</b></code> dans le cache.
		 * @param name Nom de la variable à sauvegarder.
		 */
		protected function save(name:String):void
		{
			if(sharedObject!=null)
			{
				sharedObject.data[name]=hash.get(name);
			}
		}
		/**
		 * Supprime une variable du cache.
		 * @param name Nom de la variable à supprimer.
		 */
		protected function unsave(name:String):void
		{
			if(sharedObject!=null)
			{
				sharedObject.data[name]=null;
			}
		}
		/**
		 * Remplace toutes les occurences de type <code><b>%(name)</b></code> par leurs valeurs si la variable existe.
		 * @param texte Texte à modifier.
		 * @return Le Texte une fois toutes les occurences remplacés si elles existent.
		 *  S'il manque au moins une valeur de variable, si <code><b>Lang.DEBUG=true</b></code> alors Texte est renvoyé
		 * en conservant les occurences <code><b>%(name)</b></code> inexistantes sinon la fonction renvoie une chaine vide.
		 * @see mymyoux.core.Lang#DEBUG
		 */
		public function replace(texte:String):String
		{
			var reg:RegExp=new RegExp("\\%\\(([^\\)]+)\\)","g");
			var tab:Array=new Array();
			var missing:Boolean=false;
			var temp:Array;
			while(temp=reg.exec(texte))
			{
				tab.push(temp[1]);
			}
			for(var p:String in tab)
			{
				reg=new RegExp("\\%\\("+tab[p]+"\\)","g");
				if(!hash.containsKey(tab[p]))
				{
					missing=true;
				}
				else
				{
					texte=texte.replace(reg,hash.get(tab[p]));
				}
			}
			return missing && !Lang.DEBUG?"":texte;
		}
		/**
		 * @copy mymyoux.core.Lang#watch()
		 */
		public function watch(name:String,func:Function):void
		{
			eventDispatcher.addEventListener(HashEvent.UPDATE+name,func);
		}
		/**
		 * @copy mymyoux.core.Lang#unwatch()
		 */
		 public function unwatch(name:String,func:Function):void
		{
			eventDispatcher.removeEventListener(HashEvent.UPDATE+name,func);
		}
		/**
		 * Appelée lors de la modification d'une variable.
		 * @param event Contient la nouvelle valeur <i>(clé + valeur)</i>.
		 */
		protected function onUpdate(event:HashEvent):void
		{
			
			eventDispatcher.dispatchEvent(new HashEvent(HashEvent.UPDATE+event.key,event.key,event.value,event.bubbles,event.cancelable));
		}
	}
}